package web

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"log"
	"net/http"
	"path"
	"runtime/debug"
	"strconv"
	"toyota-server/init/global"
	j_log "toyota-server/init/j-log"
	"toyota-server/model"
	"toyota-server/utils/tools"
)

func HttpRun() {
	appMode := global.AppConfig.Section("").Key("app_mode").String()
	appPort := global.AppConfig.Section("").Key("http_port").String()
	var r *gin.Engine
	if appMode == "production" {
		gin.SetMode(gin.ReleaseMode)
		// 设置全局日志中间件
		r = gin.New()
	} else {
		r = gin.Default()
	}
	GinConfigure(r)
	r.Use(CustomRecovery(), Cors())

	r.Any("/", func(ctx *gin.Context) {
		ctx.String(200, "toyota-server http server is running on "+appPort)
	})

	r.Any("/test", func(ctx *gin.Context) {
		value := ctx.Query("value")
		i, _ := strconv.Atoi(value)
		n := uint16(i)
		binStr := tools.Uint16ToBinaryString(n)
		binArr := tools.BinaryStringToArray(binStr)
		tools.SliceReverse(&binArr)
		list := make([]string, 0)
		for key, row := range binArr {
			list = append(list, fmt.Sprintf("Bit%d=%d", key, row))
		}
		ctx.JSON(200, gin.H{
			"code": 0,
			"msg":  "success",
			"data": list,
		})
	})

	r.Any("/centrifuge/field_list", func(ctx *gin.Context) {
		data := &model.CentrifugeRaw{}
		list := data.ChangeToPointItem()
		ctx.JSON(200, gin.H{
			"code": 0,
			"msg":  "success",
			"data": map[string]interface{}{
				"list": list,
			},
		})
	})

	r.Any("/mcquay/field_list", func(ctx *gin.Context) {
		data := &model.McQuayRaw{}
		list := data.ChangeToPointItem()
		ctx.JSON(200, gin.H{
			"code": 0,
			"msg":  "success",
			"data": map[string]interface{}{
				"list": list,
			},
		})
	})

	r.Any("/centrifuge/alert_list", func(ctx *gin.Context) {
		param := struct {
			model.QueryData
		}{}
		err := ctx.ShouldBindBodyWith(&param, binding.JSON)
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数",
				"data":    err.Error(),
			})
			return
		}
		param.TimeHandle(0)
		tx := model.DB.Model(&model.Alert{})
		if param.StartTime != "" {
			tx.Where("create_time >= ?", param.StartTime)
		}
		if param.EndTime != "" {
			tx.Where("create_time <= ?", param.EndTime)
		}
		var count int64
		list := make([]*model.Alert, 0)
		err = tx.Count(&count).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
				"data":    map[string]interface{}{},
			})
			return
		}
		err = tx.Order("id DESC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		ctx.JSON(200, gin.H{
			"code":    0,
			"message": "success",
			"data": map[string]interface{}{
				"list":  list,
				"count": count,
			},
		})
	})

	j_log.LogInfo([]interface{}{"http listen on :" + appPort})
	err := r.Run(":" + appPort) // 监听http server
	if err != nil {
		log.Fatal(err.Error())
	}
}

func CustomRecovery() gin.HandlerFunc {
	return gin.CustomRecovery(func(ctx *gin.Context, any interface{}) {
		defer func() {
			if err := recover(); err != nil {
				j_log.LogError([]interface{}{"CustomRecovery panic", err})
				fmt.Println(string(debug.Stack()))
			}
		}()
		ctx.String(500, "%s %v", ctx.Request.RequestURI, any)
	})
}

func Cors() gin.HandlerFunc {
	// 注意使用此跨域 router 配置请求方法必须加上OPTIONS(可以直接用Any) , 只有POST的话会报错 404
	return func(context *gin.Context) {
		context.Header("Access-Control-Allow-Origin", "*")
		context.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token")
		context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT")
		context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
		context.Header("Access-Control-Allow-Credentials", "true")
		if context.Request.Method == "OPTIONS" {
			//context.AbortWithStatus(http.StatusNoContent)
			context.AbortWithStatus(http.StatusOK)
		}
	}

}

func GinConfigure(r *gin.Engine) {
	// 静态文件
	r.Static("/static", global.StaticPath)
	r.Static("/upload", path.Join(global.StaticPath, "upload"))
	r.Static("/src", path.Join(global.StaticPath, "src"))
	r.Static("/tmp", path.Join(global.StaticPath, "tmp"))
	r.Static("/html", path.Join(global.StaticPath, "html"))
	//r.StaticFile("/MP_verify_6zPTYlHxnIHuVKAF.txt", "./static/MP_verify_6zPTYlHxnIHuVKAF.txt")
	r.StaticFile("/favicon.ico", path.Join(global.StaticPath, "favicon.ico"))
	r.StaticFile("/robots.txt", path.Join(global.StaticPath, "robots.txt"))
	//r.Use(Cors())

}
